package com.dongzili.query.common.base;

import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Slf4j
@Configuration
@AutoConfigureAfter(SpringUtil.class)
public class AutoControllerConfig {

//    private final Logger log = LoggerFactory.getLogger(AutoControllerConfig.class);

    private static final List<String> BASE_PACKAGES = Arrays.asList(
            "com.dongzili.query.custom"
    );

    @PostConstruct
    public void setup() {
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        scanner.addIncludeFilter(new AnnotationTypeFilter(TableName.class));
        Set<AnnotatedBeanDefinition> annotatedCandidateComponents = new HashSet<>();
        for (String packageName : BASE_PACKAGES) {
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(packageName);
            for (BeanDefinition beanDefinition : candidateComponents) {
                if (beanDefinition instanceof AnnotatedBeanDefinition) {
                    annotatedCandidateComponents.add((AnnotatedBeanDefinition) beanDefinition);
                }
            }
        }
        for (AnnotatedBeanDefinition beanDefinition : annotatedCandidateComponents) {
            String className = beanDefinition.getBeanClassName();

            try {
                Class<?> entityClass = Class.forName(className);
                // 动态生成控制器类
                Class<?> controllerClass = buildControllerClass(entityClass);

                // 注册控制器 Bean
                SpringUtil.registerBean(getBeanName(controllerClass.getSimpleName()), controllerClass.getDeclaredConstructor().newInstance());
                log.info("自动注册 controller bean -> 名称:{}, 类名：{}", controllerClass.getSimpleName(), controllerClass.getName());
            } catch (ClassNotFoundException e) {
                log.error("类未找到: {}", className, e);
            } catch (ReflectiveOperationException e) {
                log.error("实例化控制器类失败: {}", className, e);
                throw new RuntimeException(e);
            }
        }
    }



    private String getBeanName(String className) {
        if (className == null || className.isEmpty()) {
            throw new IllegalArgumentException("类名不能为空");
        }
        int index = className.lastIndexOf(".");
        String simpleClassName = index != -1 ? className.substring(index + 1) : className;

        char firstChar = simpleClassName.charAt(0);
        if (firstChar >= 'A' && firstChar <= 'Z') {
            firstChar -= (char) ('A' - 'a');
        }
        return firstChar + simpleClassName.substring(1);
    }

    public Class<?> buildControllerClass(Class<?> entityClass) {
        try {
            AnnotationDescription.Builder requestMappingBuilder = AnnotationDescription.Builder.ofType(RequestMapping.class);
            requestMappingBuilder = requestMappingBuilder.defineArray("value", "/" + entityClass.getSimpleName().toLowerCase());

            try(DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
                         .subclass(TypeDescription.Generic.Builder.parameterizedType(BaseController.class, entityClass).build())
                         .name(entityClass.getPackage().getName() + ".Auto" + entityClass.getSimpleName() + "Controller")
                         .annotateType(AnnotationDescription.Builder.ofType(RestController.class).build())
                         .annotateType(requestMappingBuilder.build())
                         .make()){
                System.out.println("class loader: "+getClass().getClassLoader());
                return dynamicType.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                        .getLoaded();
            }
        } catch (Exception e) {
            log.error("生成控制器类失败: {}", entityClass.getName(), e);
            throw e;
        }
    }
}
